package example

import (
	"fmt"
	"strings"
	"sync"
)

type example struct {
	criteria         Criteria
	exCriteria       []*exCriteria
	initCriteriaOnce sync.Once
	orderBy          string
	isDistinct       bool
}

type exCriteria struct {
	typ      string
	criteria Criteria
}

func NewExample() *example {
	return &example{}
}

func (e *example) CreateCriteria() Criteria {
	if e.criteria == nil {
		e.criteria = &criteria{}
		return e.criteria
	}
	return &criteria{}
}

func (e *example) Or(criteria Criteria) Example {
	return e.addExCriteria(KeywordOr, criteria)
}

func (e *example) And(criteria Criteria) Example {
	return e.addExCriteria(KeywordAnd, criteria)
}

func (e *example) addExCriteria(typ string, criteria Criteria) Example {
	e.exCriteria = append(e.exCriteria, &exCriteria{
		typ:      typ,
		criteria: criteria,
	})
	return e
}

func (e *example) OrderBy(order string) Example {
	e.orderBy = order
	return e
}

func (e *example) Distinct(d bool) Example {
	e.isDistinct = d
	return e
}

func (e *example) IsDistinct() bool {
	return e.isDistinct
}

func (e *example) Explain() (string, []interface{}) {
	if e.criteria == nil {
		return "", nil
	}
	raw, values := e.criteria.Raw()
	if e.exCriteria != nil && len(e.exCriteria) != 0 {
		raw = fmt.Sprintf("(%s) ", raw)
		for _, criterion := range e.exCriteria {
			orRaw, orValues := criterion.criteria.Raw()
			raw += fmt.Sprintf("%s (%s) ", criterion.typ, orRaw)
			values = append(values, orValues...)
		}
	}
	if e.orderBy != "" {
		raw += fmt.Sprintf("%s %s ", KeywordOrderBy, e.orderBy)
	}
	return raw, values
}

func (e *example) String() string {
	explain, i := e.Explain()
	for _, v := range i {
		explain = strings.Replace(explain, Placeholder, fmt.Sprintf("%v", v), 1)
	}
	return explain
}
